<template>
  <!-- 主容器 -->
  <div class="chat-wrapper">
    <!-- 侧边栏历史记录按钮 -->
    <div class="history-button-container">
      <van-icon name="wap-nav" size="20" @click="openHistorySidebar" class="history-button" />
    </div>

    <ChatSidebar v-model="showSidebar" :history-list="chatHistory" @new-chat="handleNewChat"
      @select-chat="handleSelectChat" @edit-chat="handleEditChat" @delete-chat="handleDeleteChat" />

    <!-- 聊天内容容器 -->
    <div class="chat-container">
      <!-- 对话内容区域 -->
      <div class="chat-content" ref="chatContent">
        <div v-for="(msg, index) in messages" :key="index" class="message" :class="msg.role">
          <div class="message-bubble">
            <div class="message-header">
              <van-icon v-if="msg.role === 'user'" name="user-circle-o" />
              <van-image v-else round width="2.5rem" height="2.5rem" class="avatar" :src="aiAvatar" />
              <span>{{ msg.role === 'user' ? '您' : 'AI律师' }}</span>
            </div>
            <!-- 直接使用渲染后的HTML -->
            <div class="message-text" v-html="msg.renderedText || msg.content"></div>
            <!-- <div class="message-time">{{ msg.time }}</div> -->
          </div>
        </div>

        <!-- 流式响应时的加载指示器 -->
        <div v-if="isStreaming" class="message ai">
          <div class="message-bubble">
            <div class="message-header">
              <van-image round width="2.5rem" height="2.5rem" class="avatar" :src="aiAvatar" />
              <span>AI律师</span>
            </div>
            <div class="message-text">
              <!-- 流式内容直接显示渲染后的HTML -->
              <span v-html="streamingRenderedContent"></span>
              <span class="cursor">|</span>
            </div>
          </div>
        </div>
      </div>

      <!-- 底部输入区域 -->
      <div class="input-area">
        <!-- 更多功能面板 -->
        <van-popup :show="showMorePanel" position="bottom" round :style="morePanelStyle" close-on-click-overlay
          @click-overlay="showMorePanel = false">
          <div class="more-panel">
            <van-grid :column-num="4" :border="false">
              <van-grid-item icon="photo-o" text="图片" @click="handleUpload('image')" />
              <van-grid-item icon="description-o" text="文件" @click="handleUpload('file')" />
              <van-grid-item icon="video-o" text="视频" @click="handleUpload('video')" />
              <van-grid-item icon="service-o" text="音频" @click="handleUpload('audio')" />
              <!-- 移除录音选项 -->
            </van-grid>
          </div>
        </van-popup>

        <!-- 文件上传对话框 -->
        <van-dialog v-model:show="showUploadDialog" :title="uploadTitle" show-cancel-button @confirm="handleFileConfirm"
          class="upload-dialog">
          <div class="uploader-container">
            <van-uploader v-model="fileList" :after-read="afterRead" :max-count="1" :accept="uploadAccept"
              :preview-image="false">
              <!-- 自定义上传区域 -->
              <div class="custom-uploader">
                <van-icon :name="uploadIcon" size="48" :color="iconColor" />
                <div class="upload-text">{{ uploadHint }}</div>
              </div>
            </van-uploader>

            <!-- 显示已选文件信息 -->
            <div v-if="fileList.length > 0" class="file-info">
              <van-icon name="description" size="20" />
              <span class="file-name">{{ fileList[0].file.name }}</span>
              <span class="file-size">({{ formatFileSize(fileList[0].file.size) }})</span>
            </div>
          </div>
        </van-dialog>

        <div class="input-box">
          <van-button round size="small" class="more-btn" @click="toggleMorePanel">
            <van-icon name="add-o" size="20" />
          </van-button>

          <div class="input-field-container" :class="{ 'has-scroll': shouldScroll }">
            <van-field v-model="userInput" rows="1" type="textarea" placeholder="请输入法律问题..." class="input-field"
              @keyup.enter="sendMessage" @input="checkScroll" ref="inputField" />
          </div>

          <van-button size="small" type="primary" class="send-btn" @click="sendMessage"
            :disabled="!userInput.trim() || isStreaming">
            <van-icon name="guide-o" size="18" />
          </van-button>

          <van-button round size="small" class="voice-btn" @touchstart="startVoiceInput" @touchend="stopVoiceInput"
            @mousedown="startVoiceInput" @mouseup="stopVoiceInput" :disabled="isStreaming">
            <van-icon :name="isRecording ? 'pause-circle-o' : 'volume-o'" size="20" />
          </van-button>
        </div>
      </div>

      <!-- 语音输入通知 -->
      <van-notify v-model:show="showVoiceNotify" type="primary" position="bottom" :style="voiceNotifyStyle"
        class="voice-notification">
        <div class="voice-notify">
          <van-icon name="volume-o" size="16" class="pulse-icon" />
          <span>正在语音输入中... (松开结束)</span>
        </div>
      </van-notify>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onBeforeUnmount, nextTick, onMounted, computed } from 'vue';
import { showToast } from 'vant';
import axios from 'axios';
import ChatSidebar from '@/components/History.vue';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
import Avatar from '@/assets/img/robot.png';

import { ElMessage, ElMessageBox, ElNotification, ElLoading } from 'element-plus'

import RecordRTC from 'recordrtc'

import { fetchWithAuth } from '@/utils/request';
import {
  getChatHistoriesByUserNo, getChatDetailsMessages,
  deleteChatHistory, editChatHistory
} from '@/api/aichat_history';
import { lo } from 'element-plus/es/locales.mjs';

import { fetchVoiceRecognition } from '@/api/voice_recognition';


/* ============== 常量定义 ===================== */
// 用户和AI头像常量
const userAvatar = 'https://img.yzcdn.cn/vant/cat.jpeg';
const aiAvatar = Avatar;

/* ============== 基础数据状态 ===================== */
// 聊天组件的基础响应式数据

/* == 1. 聊天界面模块 == */
// 聊天容器DOM引用
const chatContent = ref<HTMLElement>();
// 用户输入内容
const userInput = ref('');
// 是否显示更多功能面板
const showMorePanel = ref(false);

// 定义聊天消息类型
interface ChatMessageItem {
  role: 'assistant' | 'user';  // 消息发送者类型：AI 或用户
  content: string;         // 原始消息文本
  renderedText?: string; // 渲染后的消息（可选，用于富文本或格式化内容）
  time?: string;         // 消息时间（格式化后的字符串，如 "14:30"）
}

// 聊天消息列表
const messages = ref([{
  role: 'assistant',
  content: '您好，我是AI法律顾问小诺，请问有什么法律问题可以帮您解答？',
  renderedText: '您好，我是AI法律顾问小诺，请问有什么法律问题可以帮您解答？',
  // time: formatTime(new Date())
}]);
// 是否应该自动滚动
const shouldScroll = ref(false);
// 输入框DOM引用
const inputField = ref<HTMLElement>();


/*  === 2. 流式输出模块  === */
// 是否正在流式输出
const isStreaming = ref(false);
// 流式输出的原始内容
const streamingRawContent = ref('');
// 流式输出的渲染后内容
const streamingRenderedContent = ref('');
// 流式输出缓冲区
const streamingBuffer = ref('');


/*  === 3. 语音输入模块  ===  */
// 是否正在录音
const isRecording = ref(false);
// 是否显示语音提示
const showVoiceNotify = ref(false);
// 语音提示计时器
const voiceNotifyTimer = ref<NodeJS.Timeout | null>();
const mediaRecorder = ref<RecordRTC | null>(null)
const audioChunks = ref<Blob[]>([])


/*  ===  4. 侧边栏模块  ===  */
// 是否显示侧边栏
const showSidebar = ref(false);

/* ===  5.聊天历史管理模块  === */
// 聊天历史记录
// 定义简单的聊天记录类型
interface ChatHistoryItem {
  userNo: string; // 用户编号
  type: string; // 对话类型：test、chat、analysis
  chatId?: string; // 对话ID（可选）
  title?: string; // 对话标题（可选）
  updateTime?: Date; // 更新时间，格式：yyyy-MM-dd
}

// 使用简单结构并添加测试记录
const chatHistory = ref<ChatHistoryItem[]>([
  {
    userNo: 'user001', // 添加用户编号
    type: 'chat',      // 添加对话类型
    chatId: '1',       // chatId
    title: '合同咨询',
    updateTime: new Date('2023-06-01') // 原time改为updateTime，并改为字符串格式
  },
  {
    userNo: 'user001',
    type: 'chat',
    chatId: '2',
    title: '劳动纠纷',
    updateTime: new Date('2023-06-02')
  },
  {
    userNo: 'user001',
    type: 'analysis',
    chatId: '3',
    title: '婚姻法律咨询',
    updateTime: new Date('2023-06-03')
  },
  {
    userNo: 'user001',
    type: 'chat',
    chatId: '4',
    title: '房产买卖纠纷',
    updateTime: new Date('2023-06-04')
  },
  {
    userNo: 'user001',
    type: 'test',
    chatId: '5',
    title: '知识产权保护',
    updateTime: new Date('2023-06-05')
  }, {
    userNo: 'user001',
    type: 'chat',
    chatId: '2',
    title: '劳动纠纷',
    updateTime: new Date('2023-06-02')
  },
  {
    userNo: 'user001',
    type: 'analysis',
    chatId: '3',
    title: '婚姻法律咨询',
    updateTime: new Date('2023-06-03')
  },
  {
    userNo: 'user001',
    type: 'chat',
    chatId: '4',
    title: '房产买卖纠纷',
    updateTime: new Date('2023-06-04')
  },
  {
    userNo: 'user001',
    type: 'test',
    chatId: '5',
    title: '知识产权保护',
    updateTime: new Date('2023-06-05')
  }
]);
// 当前聊天ID
const currentChatId = ref<string | null>(null);



/* ============== Markdown处理配置 ===================== */
// Markdown解析和净化配置
marked.setOptions({
  breaks: true,
  gfm: true,
});

// 安全渲染Markdown
const renderMarkdown = (markdown: string) => {
  try {
    const rawHtml = marked.parse(markdown);
    return DOMPurify.sanitize(rawHtml);
  } catch (error) {
    console.error('Markdown渲染错误:', error);
    return markdown;
  }
};

/* ============== 计算属性 ===================== */
// 各种计算属性定义
// 上传文件面板Style属性
const morePanelStyle = computed(() => ({
  height: '25%',
  width: isDesktop.value ? '420px' : '100%',
  left: isDesktop.value ? '50%' : '0',
  transform: isDesktop.value ? 'translateX(-50%)' : 'none',
  maxWidth: '100%'
}));

// 语音输入通知面板Style属性
const voiceNotifyStyle = computed(() => ({
  bottom: isDesktop.value ? '100px' : '180px',
  width: isDesktop.value ? '400px' : 'calc(100% - 20px)',
  left: isDesktop.value ? '50%' : '10px',
  transform: isDesktop.value ? 'translateX(-50%)' : 'none',
  margin: '0 auto',
  borderRadius: '8px'
}));

const isDesktop = computed(() => window.innerWidth >= 768);

/* ============== 工具函数 ===================== */
// 通用工具函数
// 格式化时间
function formatTime(date: Date) {
  return `${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
}

// 生成唯一聊天ID
const generateChatId = (): string => {
  return Date.now().toString(36) + Math.random().toString(36).substring(2);
};

/* ============== 聊天会话管理 ===================== */
// 打开历史记录侧边栏并刷新数据
const openHistorySidebar = async () => {
  showSidebar.value = true; // 打开侧边栏
  try {
    await fetchChatHistories(); // 刷新历史记录
  } catch (error) {
    console.error('刷新历史记录失败:', error);
    // showToast('刷新历史记录失败');
    ElMessage({
      message: '刷新历史记录失败',
      type: 'warning',
    })
  }
};

// 获取历史记录的方法
const fetchChatHistories = async () => {
  try {
    const userNo = localStorage.getItem("userNo") || "defaultUserNo";

    console.log('当前用户编号:', userNo);

    if (!userNo) {
      // showToast('用户未登录');
      ElMessage({
        message: '用户未登录',
        type: 'warning',
      })
      return;
    }

    const response = await getChatHistoriesByUserNo({
      userNo: userNo,
      type: 'chat'
    });

    console.log('获取历史记录响应:', response);
    console.log('获取历史记录响应data:', response.data);
    const realResponse = response.data;

    // 首先检查响应码是否为200
    if (realResponse.code === 200 && realResponse.data && Array.isArray(realResponse.data)) {
      console.log('获取历史记录成功 code == 200:', realResponse.data);
      // 转换数据格式并赋值给chatHistory
      chatHistory.value = realResponse.data.map((item: ChatHistoryItem) => ({
        userNo: item.userNo, // 添加用户编号
        type: item.type, // 添加对话类型, 这里应该是 'chat'
        chatId: item.chatId, // 直接使用chatId作为唯一标识
        title: item.title || '未命名对话',
        updateTime: item.updateTime ? new Date(item.updateTime) : new Date()
      }))

      console.log('更新后的历史记录:', chatHistory.value);
    } else {
      console.warn('获取历史记录响应异常:', response);
      // showToast(response.msg || '获取历史记录失败');
      ElMessage({
        message: response.msg || '获取历史记录失败',
        type: 'warning',
      })
    }
  } catch (error) {
    console.error('获取历史记录失败:', error);
    ElMessage({
      message: '获取历史记录失败',
      type: 'warning',
    })
  }
};

// 获取当前会话的历史记录
const fetchChatDetailsHistories = async () => {
  try {

    console.log('当前对话currentChatId.value:', currentChatId.value);
    if (!currentChatId.value) {
      console.error('currentChatId 为空');
      return;
    }

    const response = await getChatDetailsMessages(currentChatId.value);

    console.log('获取 上下文历史对话 记录响应:', response);
    console.log('获取 上下文历史对话 记录响应data:', response.data);
    const realResponse = response.data;

    // 首先检查响应码是否为200
    if (realResponse.code === 200 && realResponse.data && Array.isArray(realResponse.data)) {
      console.log('获取 上下文历史对话 记录成功 code == 200:', realResponse.data);
      // 转换数据格式并赋值给chatHistory
      messages.value = realResponse.data.map((item: ChatMessageItem) => ({
        role: item.role, // 添加对话类型, 这里应该是 'chat'
        content: item.content, // 直接使用chatId作为唯一标识
        renderedText: renderMarkdown(item.content), // 渲染Markdown内容
      }))

      console.log('更新后的历史记录:', chatHistory.value);

      // 自动滚动到底部
      scrollToBottom();
    } else {
      console.warn('获取历史记录响应异常:', response);
      // showToast(response.msg || '获取历史记录失败');
      ElMessage({
        message: response.msg || '获取历史记录失败',
        type: 'warning',
      })
    }
  } catch (error) {
    console.error('获取历史记录失败:', error);
    ElMessage({
      message: '获取历史记录失败',
      type: 'warning',
    })
  }
};


// 删除用户某个对话的历史记录
const delChatHistory = async (chatId: string) => {
  try {
    const userNo = localStorage.getItem("userNo") || "defaultUserNo";

    console.log('删除的对话id:', chatId);


    if (!userNo) {
      // showToast('用户未登录');
      ElMessage({
        message: '用户未登录',
        type: 'warning',
      })
      return;
    }

    if (!chatId) {
      // showToast('当前没有对话');
      ElMessage({
        message: '当前没有对话',
        type: 'warning',
      })
      return;
    }

    const request = {
      type: 'chat',
      userNo: userNo,
      chatId: chatId
    }

    console.log('删除对话请求:', request);

    // 调用API删除
    const response = await deleteChatHistory(request);

    if (response == null) {
      // showToast('删除对话返回结果response为null！');
      ElMessage({
        message: '删除对话返回结果response为null！',
        type: 'warning',
      })
      return;
    }


    console.log('删除对话响应:', response);

    const realResponse = response.data;

    if (realResponse.code === 200) {
      // 从本地历史记录中删除
      chatHistory.value = chatHistory.value.filter(c => c.chatId !== chatId);

      // 如果删除的是当前对话，重置状态
      if (currentChatId.value === chatId) {
        currentChatId.value = null;
        messages.value = [{
          role: 'assistant',
          content: '请选择或创建一个新对话',
          renderedText: '请选择或创建一个新对话'
        }];
      }

      // showToast('删除成功');
      ElMessage({
        message: '删除成功',
        type: 'success',
      })
    } else {
      // showToast(realResponse.msg || '删除对话失败');
      ElMessage({
        message: realResponse.msg || '删除对话失败',
        type: 'warning',
      })
    }
  } catch (error) {
    console.error('删除对话失败:', error);
    // showToast('删除对话失败');
    ElMessage({
      message: '删除对话失败',
      type: 'warning',
    })
  }
};


// 修改用户某个对话的历史记录（标题）
const editChatHistoryTitle = async (editedChat: any) => {
  try {
    const userNo = localStorage.getItem("userNo") || "defaultUserNo";

    if (!userNo) {
      // showToast('用户未登录');
      ElMessage({
        message: '用户未登录',
        type: 'warning',
      })
      return;
    }

    if (!editedChat.chatId) {
      // showToast('当前没有对话');
      ElMessage({
        message: '当前没有对话',
        type: 'warning',
      })
      return;
    }

    const response = await editChatHistory({
      type: 'chat',
      userNo: userNo,
      chatId: editedChat.chatId,
      title: editedChat.title
    });

    console.log('修改历史会话Title:', response);
    console.log('修改历史会话Title响应data:', response.data);
    const realResponse = response.data;

    // 首先检查响应码是否为200
    if (realResponse.code === 200) {
      console.log('修改历史会话Title成功 code == 200:', realResponse.data);

      console.log('修改历史会话Title:', chatHistory.value);
    } else {
      console.warn('修改历史会话Title响应异常:', response);
      // showToast(response.msg || '修改历史会话Title失败');
      ElMessage({
        message: response.msg || '修改历史会话Title失败',
        type: 'warning',
      })
    }
  } catch (error) {
    console.error('修改历史会话Title失败:', error);
    // showToast('修改历史会话Title失败');
    ElMessage({
      message: '修改历史会话Title失败',
      type: 'warning',
    })

  }
};

// 聊天会话的CRUD操作
// 1. 创建新对话
const handleNewChat = () => {
  currentChatId.value = generateChatId();
  const welcomeMessage = {
    role: 'assistant',
    content: '您好，我是AI法律顾问，请问有什么法律问题可以帮您解答？',
    renderedText: '您好，我是AI法律顾问，请问有什么法律问题可以帮您解答？',
    // time: formatTime(new Date())
  };
  messages.value = [welcomeMessage];
  //  不用保存，当在对话中发送消息时，会自动添加到会话历史中
  // chatHistory.value.unshift({ // 添加新对话到历史记录,unshift()方法将新对话添加到数组的开头
  //   id: currentChatId.value,
  //   title: '新对话',
  //   time: new Date()
  // });
  // showToast('新对话已创建');
  ElMessage({
    message: '新对话已创建',
    type: 'success',
  })
};

// 2. 选择并加载历史对话
const handleSelectChat = (chat: any) => {

  // 设置当前聊天ID
  currentChatId.value = chat.chatId !== undefined ? chat.chatId : null;

  console.log('选择的对话chat:', chat);
  console.log('选择的对话id:', currentChatId.value);

  const loadingMessage = {
    role: 'assistant',
    content: `正在加载对话【${chat.title}】的历史记录...`,
    renderedText: `正在加载对话【${chat.title}】的历史记录...`,
  };

  messages.value = [loadingMessage];

  // 加载历史记录
  fetchChatDetailsHistories();

  // showToast(`已切换到对话: ${chat.title}`);
  ElMessage({
    message: `已切换到对话: ${chat.title}`,
    type: 'success',
  })
};



// 3. 编辑对话信息
const handleEditChat = (editedChat: any) => {
  const index = chatHistory.value.findIndex(c => c.chatId === editedChat.chatId);
  if (index !== -1) {
    chatHistory.value[index] = { ...editedChat };
    editChatHistoryTitle(editedChat);
    // showToast('对话已更新');
    ElMessage({
      message: '对话已更新',
      type: 'success',
    })
  }
};

// 4. 删除对话
const handleDeleteChat = async (chatId: string) => {
  console.log('删除的对话id:', chatId);
  delChatHistory(chatId);
};

/* ============== 输入框处理 ===================== */
// 输入框相关逻辑
const checkScroll = () => {
  nextTick(() => {
    if (inputField.value) {
      const field = inputField.value.$el.querySelector('textarea');
      if (field) {
        shouldScroll.value = field.scrollHeight > 150;
        if (shouldScroll.value) {
          field.style.height = '150px';
          field.style.overflowY = 'auto';
        } else {
          field.style.height = 'auto';
          field.style.height = field.scrollHeight + 'px';
          field.style.overflowY = 'hidden';
        }
      }
    }
  });
};

// 展示更多面板
const toggleMorePanel = () => {
  showMorePanel.value = !showMorePanel.value;
};

/* ============== 消息发送处理模块 ===================== */

/**
 * 发送用户消息并处理AI的流式响应
 * 1. 校验输入有效性
 * 2. 创建新对话记录（如需要）
 * 3. 发送消息到后端API
 * 4. 处理流式响应数据
 */
const sendMessage = async () => {
  // 检查输入是否为空或是否正在流式接收数据
  if (!userInput.value.trim() || isStreaming.value) return;

  // 如果没有当前对话ID，创建新对话、并添加到历史记录中
  if (!currentChatId.value) {
    currentChatId.value = generateChatId();
  }

  // 构造用户消息对象
  const userMessage = {
    role: 'user',       // 消息类型：用户
    content: userInput.value, // 原始文本
    renderedText: userInput.value, // 渲染后文本（此处与原始文本相同）
    // time: formatTime(new Date()) // 格式化时间
  };

  // 添加到消息列表并重置输入框
  messages.value.push(userMessage);
  userInput.value = '';
  scrollToBottom(); // 滚动到底部

  // 初始化流式接收状态
  isStreaming.value = true;
  streamingRawContent.value = '';
  streamingRenderedContent.value = '';
  streamingBuffer.value = '';

  try {
    // 发送API请求（使用axios）

    const userNo = localStorage.getItem("userNo") || "defaultUserNo";

    console.log('userNo:', userNo);


    if (!userNo) {
      // showToast('用户未登录');
      ElMessage({
        message: '用户未登录',
        type: 'warning',
      })
      return;
    }

    const response = await fetchWithAuth('/api/ai/chat/stream', {
      method: 'POST',
      body: JSON.stringify({
        userNo: userNo,
        type: 'chat',
        chatId: currentChatId.value,
        prompt: userMessage.content
      })
    });

    // const response = await fetch('/api/ai/chat/stream', {
    //   method: 'POST',
    //   headers: {
    //     'Content-Type': 'application/json',
    //   },
    //   body: JSON.stringify({
    //     userNo: 'US20216637', // 示例用户编号
    //     type: 'chat',
    //     chatId: currentChatId.value,
    //     prompt: userMessage.text
    //   })
    // });

    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    if (!response.body) throw new Error('No response body');

    // 创建读取流
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let receivedLength = 0; // 记录已接收数据长度

    // 持续读取流数据
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      receivedLength += value.length;
      const chunk = decoder.decode(value, { stream: true });

      // 处理数据块
      processStreamData(chunk);

      // 添加小延迟以确保UI更新
      await new Promise(resolve => setTimeout(resolve, 50));
    }


    // const response = await axios({
    //   method: 'post',
    //   url: '/ai/chat/stream',
    //   baseURL: 'http://localhost:8080', // 后端API地址
    //   data: {
    //     userNo: 'US20216637',     // 用户编号
    //     type: 'chat',             // 请求类型
    //     chatId: currentChatId.value, // 对话ID
    //     prompt: userMessage.text  // 用户输入内容
    //   },
    //   responseType: 'stream', // 流式响应类型
    //   // 处理下载进度事件（接收流式数据）
    //   onDownloadProgress: (progressEvent: any) => {
    //     const chunk = progressEvent.event.target.responseText;
    //     processStreamData(chunk); // 处理流式数据块
    //   }
    // });

    // 流式接收完成
    completeStreaming();
  } catch (error) {
    console.error('请求失败:', error);
    ElMessage({
      message: "请求失败，请稍后再试!",
      type: 'warning',
    })
    handleStreamError(); // 处理错误情况
  }
};

/**
 * 处理流式数据块
 * @param fullResponse 从流式接口接收到的完整响应文本
 */
const processStreamData = (chunk: string) => {
  // try {
  //   // 获取新到达的数据部分
  //   const newContent = fullResponse.slice(streamingBuffer.value.length);
  //   if (newContent) {
  //     // 更新缓冲区
  //     streamingBuffer.value = fullResponse;
  //     // 追加到原始内容
  //     streamingRawContent.value += newContent;
  //     // 渲染Markdown内容
  //     streamingRenderedContent.value = renderMarkdown(streamingRawContent.value);
  //     // 滚动到底部
  //     scrollToBottom();
  //   }
  // } catch (error) {
  //   console.error('处理流式数据时出错:', error);
  // }

  try {
    // 直接追加新数据块到原始内容
    streamingRawContent.value += chunk;

    // 立即渲染当前所有内容
    streamingRenderedContent.value = renderMarkdown(streamingRawContent.value);

    // 滚动到底部
    scrollToBottom();
  } catch (error) {
    console.error('处理流式数据时出错:', error);
    ElMessage({
      message: "处理流式数据时出错，请稍后再试!",
      type: 'warning',
    })
  }

};

/**
 * 流式接收完成处理
 * 1. 将最终内容添加到消息列表
 * 2. 重置流式接收状态
 */
const completeStreaming = () => {
  isStreaming.value = false;
  // 渲染最终Markdown内容
  const finalRenderedContent = renderMarkdown(streamingRawContent.value);
  // 添加AI消息到消息列表
  messages.value.push({
    role: 'assistant', // 消息类型：AI
    content: streamingRawContent.value, // 原始文本
    renderedText: finalRenderedContent, // 渲染后文本
    // time: formatTime(new Date()) // 格式化时间
  });
  // 重置流式接收状态
  streamingRawContent.value = '';
  streamingRenderedContent.value = '';
  streamingBuffer.value = '';
  scrollToBottom(); // 滚动到底部
};

/**
 * 处理流式接收错误
 * 1. 添加错误消息到消息列表
 * 2. 重置流式接收状态
 */
const handleStreamError = () => {
  isStreaming.value = false;
  // 构造错误消息
  const errorMessage = {
    role: 'assistant',
    content: '抱歉，请求AI服务时出现错误，请稍后再试。',
    renderedText: '抱歉，请求AI服务时出现错误，请稍后再试。',
    // time: formatTime(new Date())
  };
  // 添加到消息列表
  messages.value.push(errorMessage);
  // 重置流式接收状态
  streamingRawContent.value = '';
  streamingRenderedContent.value = '';
  streamingBuffer.value = '';
  scrollToBottom(); // 滚动到底部
};

/* ============== 滚动控制 ===================== */
// 滚动相关函数
const scrollToBottom = () => {
  nextTick(() => {
    if (chatContent.value) {
      chatContent.value.scrollTop = chatContent.value.scrollHeight;
    }
  });
};

/* ============== 语音输入处理 ===================== */
// 综合检查函数（带Element-Plus提示）
async function checkMicrophonePermission() {
  try {
    // 1. 检查权限API是否可用
    if (!navigator.permissions || !navigator.permissions.query) {
      console.warn('Permissions API not supported')
      ElMessage.warning('当前浏览器不支持高级权限查询API')
    } else {
      const permissionStatus = await navigator.permissions.query({ name: 'microphone' })
      console.log('PermissionStatus:', permissionStatus.state)

      if (permissionStatus.state === 'denied') {
        ElMessageBox.alert('麦克风访问已被永久拒绝，请手动修改浏览器权限设置', '权限提示', {
          confirmButtonText: '我明白了',
          type: 'warning'
        })
        return false
      }
    }

    // 2. 检查媒体设备支持
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      const errorMsg = '当前浏览器不支持媒体设备API'
      console.warn(errorMsg)
      ElNotification.error({
        title: '浏览器不支持',
        message: errorMsg,
        duration: 5000
      })
      throw new Error(errorMsg)
    }

    // 3. 显示加载状态
    const loading = ElLoading.service({
      lock: true,
      text: '正在请求麦克风权限...',
      spinner: 'el-icon-loading'
    })

    // 4. 尝试获取麦克风
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: {
        sampleRate: 16000,
        channelCount: 1,
        echoCancellation: true,
        noiseSuppression: true
      }
    }).finally(() => loading.close())

    // 5. 打印实际配置
    const [audioTrack] = stream.getAudioTracks()
    console.log('实际音频配置:', audioTrack.getSettings())

    // 6. 立即释放
    audioTrack.stop()

    // ElMessage.success('麦克风检查通过，设备可用')
    console.log('麦克风检查通过，设备可用');
    return true
  } catch (error: any) {
    console.error('麦克风检查失败:', error.name, error.message)

    if (error.name === 'NotAllowedError') {
      await ElMessageBox.confirm(
        '麦克风访问被拒绝，是否前往设置页面修改权限？',
        '权限被拒绝',
        {
          confirmButtonText: '去设置',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).then(() => {
        // 通常浏览器不允许直接跳转权限设置页
        ElMessage.info('请在浏览器地址栏右侧点击权限图标进行设置')
      })
    } else {
      ElNotification.error({
        title: '麦克风检查失败',
        message: error.message || '未知错误',
        duration: 5000
      })
    }

    return false
  }
}

// 执行检查
checkMicrophonePermission();


// 语音输入相关功能
const startVoiceInput = async () => {
  if (isStreaming.value || isRecording.value) {
    ElMessage.info('请等待当前操作完成');
    return;
  }

  try {
    // 重置状态（防止之前的状态残留）
    resetVoiceInputState();

    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    stream.getTracks().forEach(track => track.onended = () => {
      if (isRecording.value) stopVoiceInput();
    });

    // 语音录制配置（严格匹配华为8k要求）
    mediaRecorder.value = new RecordRTC(stream, {
      type: 'audio',
      mimeType: 'audio/wav',
      desiredSampRate: 8000,      // 严格匹配后端属性
      numberOfAudioChannels: 1,   // 单声道
      bufferSize: 2048,           // 8k推荐缓冲区
      recorderType: RecordRTC.StereoAudioRecorder,
      audioBitsPerSecond: 128000, // 16bit * 8kHz = 128kbps
      disableLogs: true,          // 关闭所有日志
      timeSlice: 1000, // 增加分片处理
    });

    // 添加WAV格式校验
    mediaRecorder.value.onAudioProcessStarted = () => {
      console.log('音频格式:', mediaRecorder.value?.getInternalRecorder()?.mimeType);
    };

    mediaRecorder.value.onError = () => {
      handleVoiceError(new Error('录音设备异常'));
    };

    isRecording.value = true;
    showVoiceNotify.value = true;
    mediaRecorder.value.startRecording();

    // 安全计时器（自动停止+资源清理）
    const safetyTimer = setTimeout(() => {
      if (isRecording.value) stopVoiceInput();
    }, 30000);

    // 确保计时器会被清除
    onBeforeUnmount(() => clearTimeout(safetyTimer));

  } catch (error) {
    handleVoiceError(error);
  }
};

// 停止语音输入（自动处理成功/失败状态）
const stopVoiceInput = async () => {
  if (!isRecording.value) return;

  // 立即更新状态（避免重复触发）
  isRecording.value = false;
  showVoiceNotify.value = false;

  try {
    if (!mediaRecorder.value) throw new Error('录音器未初始化');

    const currentRecorder = mediaRecorder.value;
    mediaRecorder.value = null;

    const blob = await new Promise<Blob>((resolve, reject) => {
      currentRecorder.stopRecording(() => {
        try {
          const result = currentRecorder.getBlob();
          if (!result?.size) reject(new Error('录音数据为空'));
          else resolve(result);
        } catch (e) {
          reject(e);
        } finally {
          currentRecorder.destroy();
        }
      });

      setTimeout(() => reject(new Error('录音处理超时')), 5000);
    });

    ElMessage.info('语音识别中...');
    userInput.value = await fetchVoiceRecognition(
      new Blob([blob], { type: 'audio/wav' }),
      { language: 'chinese', timeout: 30000 }
    );

    ElMessage.success('语音输入完成');

  } catch (error) {
    handleVoiceError(error);
  } finally {
    resetVoiceInputState();
  }
};

// 统一错误处理
const handleVoiceError = (error: unknown) => {
  const message = error instanceof Error ? error.message : '语音处理失败';
  console.error('语音错误:', error);
  ElMessage.error(message);
  resetVoiceInputState();
};

// 强制重置所有状态
const resetVoiceInputState = () => {
  isRecording.value = false;
  showVoiceNotify.value = false;

  if (mediaRecorder.value) {
    mediaRecorder.value.destroy().catch(console.error);
    mediaRecorder.value = null;
  }
};

// 组件卸载时清理
onBeforeUnmount(resetVoiceInputState);

/* ============== 文件上传对话框模块 ===================== */
// 控制上传对话框的显示状态
const showUploadDialog = ref(false);

// 存储已选择的文件列表
const fileList = ref<any[]>([]);

// 当前上传类型（图片/文件/视频/音频）
const uploadType = ref<'image' | 'file' | 'video' | 'audio'>('file');

// 文件选择器的accept属性值
const uploadAccept = ref<string>('*/*');

/**
 * 格式化文件大小为可读字符串
 * @param bytes 文件大小（字节）
 * @returns 格式化后的文件大小字符串（如"2.5 MB"）
 */
const formatFileSize = (bytes: number) => {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
};

/**
 * 计算上传对话框标题（根据上传类型变化）
 */
const uploadTitle = computed(() => {
  switch (uploadType.value) {
    case 'image': return '上传图片';
    case 'video': return '上传视频';
    case 'audio': return '上传音频';
    default: return '上传文件';
  }
});

/**
 * 计算上传图标（根据上传类型变化）
 */
const uploadIcon = computed(() => {
  switch (uploadType.value) {
    case 'image': return 'photo-o';
    case 'video': return 'video-o';
    case 'audio': return 'service-o';
    default: return 'description';
  }
});

/**
 * 计算图标颜色（有文件时显示主题色，无文件时显示灰色）
 */
const iconColor = computed(() => {
  return fileList.value.length > 0 ? '#1989fa' : '#969799';
});

/**
 * 计算上传提示文本（根据上传类型和是否有文件变化）
 */
const uploadHint = computed(() => {
  if (fileList.value.length > 0) return '点击更换文件';
  switch (uploadType.value) {
    case 'image': return '点击选择图片';
    case 'video': return '点击选择视频';
    case 'audio': return '点击选择音频';
    default: return '点击选择文件';
  }
});

/**
 * 处理上传按钮点击事件
 * @param type 上传类型（image/file/video/audio）
 */
const handleUpload = (type: 'image' | 'file' | 'video' | 'audio') => {
  // 设置上传类型
  uploadType.value = type;
  // 关闭更多面板
  showMorePanel.value = false;

  // 根据类型设置文件选择器的accept属性
  switch (type) {
    case 'image':
      uploadAccept.value = 'image/*';
      break;
    case 'video':
      uploadAccept.value = 'video/*';
      break;
    case 'audio':
      uploadAccept.value = 'audio/*';
      break;
    default:
      uploadAccept.value = '*/*';
  }

  // 显示上传对话框并清空文件列表
  showUploadDialog.value = true;
  fileList.value = [];
};

/**
 * 文件选择后的回调函数
 * @param file 选择的文件对象
 */
const afterRead = (file: any) => {
  console.log('文件已选择:', file);
  // TODO 这里可以添加文件预览或预处理逻辑
};

/**
 * 确认文件上传
 */
const handleFileConfirm = () => {
  // 检查是否已选择文件
  if (fileList.value.length === 0) {
    // showToast('请先选择文件');
    ElMessage({
      message: '请先选择文件',
      type: 'warning',
    })
    return;
  }

  // 获取第一个文件并显示提示
  const file = fileList.value[0].file;
  // showToast(`已选择${uploadType.value}文件: ${file.name}`);
  ElMessage({
    message: `已选择${uploadType.value}文件: ${file.name}`,
    type: 'success',
  })

  // 关闭上传对话框

  // 重置状态
  fileList.value = [];
  showUploadDialog.value = false;

  // TODO 这里可以添加实际的上传逻辑...
};


/* ============== 生命周期钩子 ===================== */
// 组件生命周期函数
onMounted(() => {
  scrollToBottom();

  fetchChatHistories(); // 获取聊天历史记录
});

</script>




<style scoped>
/* =================================== */
/* 基础布局 */
.chat-wrapper {
  position: relative;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
}

.chat-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: calc(100vh - var(--van-nav-bar-height) - var(--van-tabbar-height) - env(safe-area-inset-bottom));
  background-color: #f7f8fa;
  position: relative;
  overflow: hidden;
}

/* =================================== */

/* 历史按钮 */
.history-button-container {
  position: fixed;
  top: calc(var(--van-nav-bar-height) + 10px);
  left: 10px;
  z-index: 1001;
}

.history-button {
  background-color: white;
  padding: 8px;
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 1001;
}

/* =================================== */
/* 聊天内容区域 */
.chat-content {
  flex: 1;
  padding: 12px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
}

/* =================================== */
/* 消息样式 */
.message {
  margin-bottom: 16px;
  display: flex;
}

.message.user {
  justify-content: flex-end;
}

.message.ai {
  justify-content: flex-start;
}

.message-bubble {
  max-width: 75%;
  padding: 12px 16px;
  border-radius: 18px;
  position: relative;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
  transition: all 0.2s ease;
  line-height: 1.5;
}

.message.user .message-bubble {
  background-color: #1989fa;
  color: white;
  border-bottom-right-radius: 4px;
}

.message.ai .message-bubble {
  background-color: white;
  color: #333;
  border-bottom-left-radius: 4px;
}

.message-header {
  font-size: 12px;
  margin-bottom: 4px;
  display: flex;
  align-items: center;
}

.message-header .van-icon {
  margin-right: 4px;
}

.message.user .message-header {
  color: rgba(255, 255, 255, 0.8);
}

.message.ai .message-header {
  color: #999;
}

.message-text {
  word-break: break-word;
  line-height: 1.5;
}

.message-time {
  font-size: 10px;
  text-align: right;
  margin-top: 4px;
  opacity: 0.7;
}

/* =================================== */
/* 输入区域 */
.input-area {
  padding: 12px;
  background-color: white;
  border-bottom: 1px solid #f0f0f0;
  border-radius: 16px;
  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.08);
  position: sticky;
  bottom: 0;
  z-index: 100;
}


.input-box {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.input-field-container {
  flex: 1;
  position: relative;
  min-height: 40px;
  max-height: 150px;
  border-radius: 18px;
  background-color: #f7f8fa;
  box-shadow:
    inset 0 1px 3px rgba(0, 0, 0, 0.05),
    0 1px 2px rgba(0, 0, 0, 0.05);
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
}

.input-field-container.has-scroll {
  overflow-y: auto;
}

.input-field {
  width: 100%;
  min-height: 40px;
  max-height: 150px;
  padding: 10px 16px;
  box-sizing: border-box;
  overflow: hidden;
  border: none;
  outline: none;
  line-height: 1.5;
  font-size: 14px;
  background-color: transparent;
  resize: none;
}

.input-field-container.has-scroll .input-field {
  overflow-y: auto;
}

.input-field :deep(.van-field__control) {
  min-height: 40px;
  display: flex;
  align-items: center;
}

.input-field-container.has-scroll .input-field :deep(.van-field__control) {
  align-items: flex-start;
  min-height: auto;
}

.input-field::-webkit-scrollbar {
  width: 4px;
}

.input-field::-webkit-scrollbar-thumb {
  background-color: rgba(0, 0, 0, 0.2);
  border-radius: 2px;
}

.input-field::-webkit-scrollbar-track {
  background-color: transparent;
}

/* =================================== */
/* 按钮样式 */
.more-btn,
.voice-btn,
.send-btn {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
  border: none;
  transition: all 0.2s ease;
  flex-shrink: 0;
  margin-bottom: 5px;
}

.more-btn,
.voice-btn {
  width: 40px;
  background-color: #f7f8fa;
  color: #1989fa;
  border-radius: 50%;
}

.send-btn {
  border-radius: 18px;
  font-weight: 500;
}

.send-btn:disabled {
  opacity: 0.5;
}

/* =================================== */

/* 更多面板 */
.more-panel {
  padding: 16px;
}

.van-uploader {
  padding: 16px;
  text-align: center;
}

.van-uploader__upload {
  width: 100%;
  height: 100px;
  margin: 0 auto;
}

/* =================================== */

/* 上传对话框样式 */
.upload-dialog {
  text-align: center;
}

.uploader-container {
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.custom-uploader {
  width: 120px;
  height: 120px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  border: 1px dashed #ebedf0;
  border-radius: 8px;
  background-color: #f7f8fa;
  margin: 0 auto 16px;
  cursor: pointer;
  transition: all 0.3s;
}

.custom-uploader:hover {
  border-color: #1989fa;
  background-color: #f0f7ff;
}

.upload-text {
  margin-top: 8px;
  font-size: 14px;
  color: #969799;
}

.file-info {
  margin-top: 12px;
  padding: 8px 12px;
  background-color: #f7f8fa;
  border-radius: 4px;
  display: flex;
  align-items: center;
  max-width: 100%;
}

.file-name {
  margin: 0 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

.file-size {
  color: #969799;
  font-size: 12px;
}


/* =================================== */

/* 语音通知 */
.voice-notification {
  transform: translateY(0) !important;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15) !important;
}

.voice-notify {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  font-size: 14px;
}

.pulse-icon {
  margin-right: 8px;
  animation: pulse 1.5s infinite;
}

/* =================================== */

/* 动画 */
@keyframes pulse {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.5;
  }
}

@keyframes blink {

  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0;
  }
}

.cursor {
  animation: blink 1s infinite;
  opacity: 1;
}

/* =================================== */

/* 响应式设计 - 移动端 */
@media (max-width: 767px) {
  .chat-container {
    height: calc(100dvh - var(--van-nav-bar-height) - var(--van-tabbar-height) - env(safe-area-inset-bottom));
  }

  .message-bubble {
    max-width: 85%;
  }

  .input-field-container {
    max-height: 100px;
  }

  .input-field {
    max-height: 50px;
  }

  .more-btn,
  .voice-btn {
    width: 36px;
    height: 36px;
  }

  .send-btn {
    height: 36px;
  }
}

/* 响应式设计 - PC端 */
@media (min-width: 768px) {
  .chat-container {
    width: 420px;
    margin: 0 auto;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
    height: calc(100vh - var(--van-nav-bar-height) - 20px);
    margin-top: 10px;
    margin-bottom: 10px;
  }

  .history-button-container {
    left: calc(50% - 200px);
  }

  .input-field-container {
    max-height: 150px;
  }

  .input-field {
    max-height: 50px;
  }
}

/* =================================== */

/* Markdown样式 */
.message-text :deep(h1),
.message-text :deep(h2),
.message-text :deep(h3) {
  margin: 1em 0 0.5em;
  line-height: 1.2;
}

.message-text :deep(p) {
  margin: 0.5em 0;
}

.message-text :deep(ul),
.message-text :deep(ol) {
  padding-left: 1.5em;
  margin: 0.5em 0;
}

.message-text :deep(li) {
  margin: 0.25em 0;
}

.message-text :deep(blockquote) {
  border-left: 3px solid #ddd;
  padding-left: 1em;
  margin: 0.5em 0;
  color: #666;
}

.message-text :deep(pre) {
  background-color: #f6f8fa;
  padding: 1em;
  border-radius: 4px;
  overflow-x: auto;
  margin: 0.5em 0;
}

.message-text :deep(code) {
  font-family: monospace;
  background-color: rgba(175, 184, 193, 0.2);
  padding: 0.2em 0.4em;
  border-radius: 4px;
  font-size: 85%;
}

.message-text :deep(a) {
  color: #1989fa;
  text-decoration: none;
}

.message-text :deep(a:hover) {
  text-decoration: underline;
}

.message-text :deep(table) {
  border-collapse: collapse;
  width: 100%;
  margin: 0.5em 0;
}

.message-text :deep(th),
.message-text :deep(td) {
  border: 1px solid #ddd;
  padding: 0.5em;
}

.message-text :deep(th) {
  background-color: #f6f8fa;
}

/* =================================== */
</style>